﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Netcached.Hash;
using System.Collections.Specialized;

namespace Netcached
{
    class ServerCluster : IDisposable
    {
        IConsistentHashing consistentHashingService;
        Dictionary<string, SocketPool> socketPoolMap;
        bool disposed;

        public ServerCluster(IEnumerable<ServerDefinition> servers, int maxAliveSockets)
        {
            string[] serverAddresses = servers.Select(x => x.Address).ToArray();

            ValidateServerAddress(serverAddresses);
            consistentHashingService = new KetamaHashing(serverAddresses);

            socketPoolMap = new Dictionary<string, SocketPool>();
            foreach (var server in servers)
            {
                var socketPool = new SocketPool(server.Address, server.Port, server.SendReceiveTimeout, maxAliveSockets);
                socketPoolMap.Add(server.Address, socketPool);
            }
        }

        private void ValidateServerAddress(string[] servers)
        {
            foreach (var address in servers)
            {
                if (address == null || Uri.CheckHostName(address) == UriHostNameType.Unknown)
                {
                    throw new ArgumentException(string.Format("Server address '{0}' is not a valid host name or an IP address", address));
                }
            }
        }

        public SocketWrapper GetSocketForKey(string objectKey)
        {
            string serverName = consistentHashingService.GetServerAddress(objectKey);
            var socketPool = socketPoolMap[serverName];

            return socketPool.GetSocket();
        }

        public Dictionary<string, SocketWrapper> GetSocketsForKeys(string[] objectKeys)
        {
            var socketDictionary = new Dictionary<string, SocketWrapper>();
            var socketList = new List<SocketWrapper>();
            
            foreach (string objectKey in objectKeys)
            {
                string server = consistentHashingService.GetServerAddress(objectKey);

                var socketForServer = socketList.FirstOrDefault(x => x.ServerAddress == server);
                if (socketForServer == null)
                {
                    var socketPool = socketPoolMap[server];
                    socketForServer = socketPool.GetSocket();
                    socketList.Add(socketForServer);
                }

                socketDictionary.Add(objectKey, socketForServer);
            }

            return socketDictionary;
        }

        public List<SocketWrapper> GetSocketsForAllServers()
        {
            var socketWrapperList = new List<SocketWrapper>();
            foreach (var socketPool in socketPoolMap.Values)
            {
                socketWrapperList.Add(socketPool.GetSocket());
            }

            return socketWrapperList;
        }

        public void Dispose()
        {
            foreach (var socketPool in socketPoolMap)
            {
                socketPool.Value.Dispose();
            }
        }
    }
}
